package cn.xingzhe.monster.user.domain.model;

import cn.xingzhe.monster.user.domain.enums.CaptchaTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.UUID;
import java.util.regex.Pattern;

/**
 * 验证码领域模型
 * 包含验证码相关的业务逻辑和业务规则
 *
 * @author System
 * @version 1.0.0
 * @since 2024-01-01
 */
@Getter
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class CaptchaModel {

    /**
     * 邮箱正则表达式（预编译）
     * 支持标准邮箱格式：用户名@域名.顶级域名
     * 用户名：字母、数字、点、下划线、连字符，1-64个字符
     * 域名：字母、数字、连字符、点，支持多级域名
     * 顶级域名：2-6个字母
     */
    private static final Pattern EMAIL_PATTERN = Pattern.compile(
            "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}@[a-zA-Z0-9][a-zA-Z0-9.-]{0,253}\\.[a-zA-Z]{2,6}$"
    );

    /**
     * 中国手机号正则表达式（预编译）
     * 规则：11位数字，1开头，第二位为3-9，后9位为0-9
     * 支持的号段：13x, 14x, 15x, 16x, 17x, 18x, 19x
     */
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");

    /**
     * 验证码正则表达式（预编译）
     * 规则：4-8位纯数字
     */
    private static final Pattern CAPTCHA_CODE_PATTERN = Pattern.compile("^\\d{4,8}$");

    /**
     * 验证码ID
     */
    private String id;

    /**
     * 键（手机号或邮箱）
     */
    private String key;

    /**
     * 验证码
     */
    private String code;

    /**
     * 验证码类型
     */
    private CaptchaTypeEnum type;

    /**
     * 过期时间
     */
    private LocalDateTime expireTime;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 创建验证码
     *
     * @param key           键（手机号或邮箱）
     * @param code          验证码
     * @param type          验证码类型
     * @param expireMinutes 有效期（分钟）
     * @return 验证码领域模型
     */
    public static CaptchaModel create(String key, String code, CaptchaTypeEnum type, int expireMinutes) {
        validateKey(key);
        validateCode(code);
        LocalDateTime now = LocalDateTime.now();
        return CaptchaModel.builder()
                .id(UUID.randomUUID().toString())
                .key(key)
                .code(code)
                .type(type)
                .expireTime(now.plusMinutes(expireMinutes))
                .createTime(now)
                .build();
    }

    /**
     * 验证验证码
     *
     * @param inputCode 输入的验证码
     * @return 是否验证通过
     */
    public boolean validate(String inputCode) {
        if (isExpired()) {
            return false;
        }
        return this.code.equals(inputCode);
    }

    /**
     * 检查是否过期
     *
     * @return 是否过期
     */
    public boolean isExpired() {
        return LocalDateTime.now().isAfter(this.expireTime);
    }

    /**
     * 检查是否可用
     *
     * @return 是否可用
     */
    public boolean canUse() {
        return !isExpired();
    }

    /**
     * 验证键格式（邮箱或手机号）
     * 使用预编译的正则表达式提高性能
     *
     * @param key 键
     */
    private static void validateKey(String key) {
        if (key == null || key.trim().isEmpty()) {
            throw new IllegalArgumentException("键（邮箱或手机号）不能为空");
        }

        // 去除首尾空格
        String trimmedKey = key.trim();

        // 使用预编译的正则表达式进行严格校验
        boolean isEmail = EMAIL_PATTERN.matcher(trimmedKey).matches();
        if (isEmail) {
            return;
        }
        boolean isPhone = PHONE_PATTERN.matcher(trimmedKey).matches();
        if (isPhone) {
            return;
        }
        throw new IllegalArgumentException("键必须是有效的邮箱或手机号格式");
    }

    /**
     * 验证验证码格式
     * 使用预编译的正则表达式提高性能
     *
     * @param code 验证码
     */
    private static void validateCode(String code) {
        if (code == null || code.trim().isEmpty()) {
            throw new IllegalArgumentException("验证码不能为空");
        }

        // 使用预编译的正则表达式进行校验
        if (!CAPTCHA_CODE_PATTERN.matcher(code).matches()) {
            throw new IllegalArgumentException("验证码必须是4-8位数字");
        }
    }

}

